<template>
  <div class="markdown-body" ref="rootEl"></div>
  <ChatFileView ref="chatFileViewRef" />
</template>

<script setup>
import { ref, watch, onMounted, nextTick } from "vue";
import ChatFileView from "../ChatFileView.vue";
import { ElMessage } from "element-plus";
import { marked } from "marked";
import hljs from "highlight.js";
import mermaid from "mermaid";
import 'highlight.js/styles/atom-one-light.css'
import { useClipboard, useEventListener } from "@vueuse/core";
const { copy } = useClipboard();

// 初始化 mermaid流程图
mermaid.initialize({
  startOnLoad: false,
  theme: 'default',
  securityLevel: 'loose',
  fontFamily: 'inherit',
  flowchart: {
    useMaxWidth: true,
    htmlLabels: true,
    curve: 'basis',
  },
});
const props = defineProps({
  content: {
    type: String,
    default: "",
  },
});

/** marked 渲染器 */
const renderer = {
  code(code, language) {
    let actualCode = code;
    let actualLanguage = language;
    // 检查 code 是否为对象
    if (typeof code === "object" && code !== null && code.type === "code") {
      actualCode = code.text;
      actualLanguage = code.lang;
    }

    // 如果是 mermaid 代码，返回特殊的容器
    if (actualLanguage === 'mermaid') {
      return `<div class="mermaid">${actualCode}</div>`;
    }

    let highlightHtml;
    try {
      highlightHtml = hljs.highlight(actualCode, {
        language: actualLanguage ? actualLanguage : "plaintext",
        ignoreIllegals: true,
      }).value;
    } catch (e) {
    }
    const copyHtml = `<div class="copy" data-copy='${actualCode}'>复制</div>`;
    return `<pre style="position: relative;">${copyHtml}<code>${highlightHtml}</code></pre>`;
  },
  link(href) {
    // 创建一个带有点击事件的链接
    const linkHtml = `<a class="link_a" href="${href.href}" title="${href.title || ""
      }" target="_blank" rel="noopener noreferrer">${href.text}</a>`;
    return linkHtml;
  },
  image(href, title, text) {
    // 为图片包裹一个div容器，并启用懒加载与异步解码，减少重绘开销
    const imgHtml = `<img src="${href.href}" alt="${text || ''}" title="${title || ''}" loading="lazy" decoding="async" />`;
    return `<div class="image-container">${imgHtml}</div>`;
  },
};

// 配置 marked
marked.use({
  renderer,
  useNewRenderer: true, // 使用新版本的渲染器
  gfm: true, // 启用GFM语法(表格需要此配置)
  tables: true, // 显式启用表格支持
  breaks: false, // 禁用行内换行符
  pedantic: false, // 禁用严格模式
  sanitize: false, // 禁用HTML转义，允许原始HTML
});

const rootEl = ref(null);

const updateWith = async (data) => {
  if (!rootEl.value) return;
  const tmpDiv = document.createElement("div");
  tmpDiv.setAttribute('class', 'markdown-body')
  tmpDiv.innerHTML = marked(data);
  deepCloneAndUpdate(rootEl.value, tmpDiv);
  
  // 渲染 MathJax
  if (window.MathJax && window.MathJax.typesetPromise) {
    try {
      await window.MathJax.typesetPromise();
    } catch (error) {
      console.warn("MathJax rendering error:", error);
    }
  }

  // 渲染 Mermaid 图表
  await nextTick();
  const mermaidElements = rootEl.value.querySelectorAll('.mermaid');
  if (mermaidElements.length > 0) {
    try {
      await mermaid.run({
        nodes: mermaidElements,
      });
    } catch (error) {
      console.warn("Mermaid rendering error:", error);
    }
  }
};


watch(
  () => props.content,
  (data) => {
    updateWith(data);
  }
);

// 图片预览和下载
const chatFileViewRef = ref(null)
const onPreview = (e) => {
  if (e?.target?.tagName != 'IMG') return
  chatFileViewRef.value.open(e?.target?.src)
}


onMounted(() => {
  if (props.content) updateWith(props.content);

  rootEl.value.addEventListener("click", (e) => {
    if (e.target.classList.contains("copy")) {
      copy(e.target?.dataset?.copy);
      ElMessage({
        message: '复制成功!',
        grouping: true,
        type: 'success',
      })
    }else if (e.target.classList.contains('preview-image') || e.target.tagName === 'IMG') {
      onPreview(e)
    }
  });
});

function deepCloneAndUpdate(div1, div2) {
  // 递归比较和更新 div1 和 div2 的子节点
  function compareAndUpdate(node1, node2) {
    // 情况 1：node1 是文本节点，更新文本内容
    if (
      node1 &&
      node1.nodeType === Node.TEXT_NODE &&
      node2.nodeType === Node.TEXT_NODE
    ) {
      if (node1.nodeValue !== node2.nodeValue) {
        // 更新文本内容
        node1.nodeValue = node2.nodeValue;
      }
      return;
    }

    // 情况 2：node1 和 node2 的标签名不同，替换整个节点
    if (!node1 || node1.tagName !== node2.tagName) {
      // 克隆 node2 节点
      const newNode = node2.cloneNode(true);
      if (node1) {
        // 替换旧节点
        node1.parentNode.replaceChild(newNode, node1);
      } else {
        // 如果 node1 不存在，直接新增
        node2.parentNode.appendChild(newNode);
      }
      return;
    }

    // 情况 3：节点的 class 或其他属性更新, 注意对root节点的保护
    if (
      node1.className !== "article-content" &&
      node1.className !== node2.className
    ) {
      // 3.1 更新 className
      node1.className = node2.className;
    }

    // 3.2 对 id 的更新 注意对root节点的保护
    if (node1.id !== "article-content" && node1.id !== node2.id) {
      node1.id = node2.id;
    }

    //  3.3 对 style 的更新
    if (node1.style.cssText !== node2.style.cssText) {
      node1.style.cssText = node2.style.cssText;
    }

    // 情况 4：递归对比和更新子节点
    const children1 = Array.from(node1.childNodes); // node1 的所有子节点
    const children2 = Array.from(node2.childNodes); // node2 的所有子节点

    // 遍历 node2 的子节点，逐个与 node1 的对应子节点比较
    children2.forEach((child2, index) => {
      const child1 = children1[index];
      if (!child1) {
        // 如果 child1 不存在，直接克隆 child2 并添加到 node1
        const newChild = child2.cloneNode(true);
        node1.appendChild(newChild);
      } else {
        // 如果 child1 存在，递归比较和更新
        compareAndUpdate(child1, child2);
      }
    });

    // 删除 node1 中多余的子节点
    if (children1.length > children2.length) {
      for (let i = children2.length; i < children1.length; i++) {
        node1.removeChild(children1[i]);
      }
    }
  }
  // 从 div2 根节点开始与 div1 比较
  compareAndUpdate(div1, div2);
}

</script>
<style lang="scss">
@import './style.scss';
</style>